<!DOCTYPE html>
            
<HTML>
<HEAD>
<meta name="booktitle" content="Developing Applications With Objective Caml" >
 <meta charset="ISO-8859-1"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<META name="GENERATOR" content="hevea 1.05-7 of 2000-02-24">
<META NAME="Author" CONTENT="Christian.Queinnec@lip6.fr">
<LINK rel=stylesheet type="text/css" href="videoc-ocda.css">
<script language="JavaScript" src="videoc.js"><!--
//--></script>
<TITLE>
 Extended Example: Managing Bank Accounts
</TITLE>
</HEAD>
<BODY class="regularBody">
<A HREF="book-ora132.html"><IMG SRC ="previous_motif.gif" ALT="Previous"></A>
<A HREF="index.html"><IMG SRC ="contents_motif.gif" ALT="Contents"></A>
<A HREF="book-ora134.html"><IMG SRC ="next_motif.gif" ALT="Next"></A>
<HR>

<H2> Extended Example: Managing Bank Accounts</H2>
We conclude this chapter by an example illustrating the main aspects
of modular programming: type abstraction, multiple views of a module,
and functor-based code reuse.<BR>
<BR>
The goal of this example is to provide two modules for managing a bank
account. One is intended to be used by the bank, and the other by the
customer. The approach is to implement a general-purpose parameterized
functor providing all the needed operations, then apply it twice to the
correct parameters, constraining it by the signature corresponding to
its final user: the bank or the customer.<BR>
<BR>
<A NAME="toc189"></A>
<H3> Organization of the Program</H3>
<BLOCKQUOTE><DIV ALIGN=center><HR WIDTH="80%" SIZE=2></DIV>
<DIV ALIGN=center>
<IMG SRC="book-ora057.gif">
<BR>
<BR>
<DIV ALIGN=center>Figure 14.1: Modules dependency graph.</DIV><BR>

<A NAME="fig-mod1"></A>
</DIV>
<DIV ALIGN=center><HR WIDTH="80%" SIZE=2></DIV></BLOCKQUOTE> 
The two end modules <TT>BManager</TT> and <TT>CManager</TT> are
obtained by constraining the module <TT>Manager</TT>. The latter
is obtained by applying the functor <TT>FManager</TT> to the
modules <TT>Account</TT>, <TT>Date</TT> and two additional modules
built by application of the functors <TT>FLog</TT>
and <TT>FStatement</TT>. Figure <A HREF="book-ora133.html#fig-mod1">14.1</A> illustrates these
dependencies. <BR>
<BR>
<A NAME="toc190"></A>
<H3> Signatures for the Module Parameters</H3>
The module for account management is parameterized by four other
modules, whose signatures we now detail.<BR>
<BR>

<H5> The bank account.</H5> This module provides the basic operations
on the contents of the account.


<PRE><BR># <B>module</B><CODE> </CODE><B>type</B><CODE> </CODE>ACCOUNT<CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>sig</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>type</B><CODE> </CODE>t<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>exception</B><CODE> </CODE>BadOperation<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>create<CODE> </CODE><CODE>:</CODE><CODE> </CODE>float<CODE> </CODE>-&gt;<CODE> </CODE>float<CODE> </CODE>-&gt;<CODE> </CODE>t<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>deposit<CODE> </CODE><CODE>:</CODE><CODE> </CODE>float<CODE> </CODE>-&gt;<CODE> </CODE>t<CODE> </CODE>-&gt;<CODE> </CODE>unit<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>withdraw<CODE> </CODE><CODE>:</CODE><CODE> </CODE>float<CODE> </CODE>-&gt;<CODE> </CODE>t<CODE> </CODE>-&gt;<CODE> </CODE>unit<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>balance<CODE> </CODE><CODE>:</CODE><CODE> </CODE>t<CODE> </CODE>-&gt;<CODE> </CODE>float<BR><CODE> </CODE><B>end</B><CODE> </CODE>;;<BR>

</PRE>

This set of functions provide the minimal operations on an account.
The creation operation takes as arguments the initial balance and the
maximal overdraft allowed. Excessive withdrawals may raise the
<TT>BadOperation</TT> exception.<BR>
<BR>

<H5> Ordered keys.</H5> Operations are recorded in an operation log
described in the next paragraph. Each log entry is identified by a
key. Key management functions are described by the following signature:


<PRE><BR># <B>module</B><CODE> </CODE><B>type</B><CODE> </CODE>OKEY<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>sig</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>type</B><CODE> </CODE>t<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>create<CODE> </CODE><CODE>:</CODE><CODE> </CODE>unit<CODE> </CODE>-&gt;<CODE> </CODE>t<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>of_string<CODE> </CODE><CODE>:</CODE><CODE> </CODE>string<CODE> </CODE>-&gt;<CODE> </CODE>t<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>to_string<CODE> </CODE><CODE>:</CODE><CODE> </CODE>t<CODE> </CODE>-&gt;<CODE> </CODE>string<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>eq<CODE> </CODE><CODE>:</CODE><CODE> </CODE>t<CODE> </CODE>-&gt;<CODE> </CODE>t<CODE> </CODE>-&gt;<CODE> </CODE>bool<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>lt<CODE> </CODE><CODE>:</CODE><CODE> </CODE>t<CODE> </CODE>-&gt;<CODE> </CODE>t<CODE> </CODE>-&gt;<CODE> </CODE>bool<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>gt<CODE> </CODE><CODE>:</CODE><CODE> </CODE>t<CODE> </CODE>-&gt;<CODE> </CODE>t<CODE> </CODE>-&gt;<CODE> </CODE>bool<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>end</B><CODE> </CODE>;;<BR>

</PRE>

The <TT>create</TT> function returns a new, unique key. The functions
<TT>of_string</TT> and <TT>to_string</TT> convert between keys and
character strings. The three remaining functions are key comparison
functions.<BR>
<BR>

<H5> History.</H5> 
Logs of operations performed on an account are represented by the
following abstract types and functions:


<PRE><BR># <B>module</B><CODE> </CODE><B>type</B><CODE> </CODE>LOG<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>sig</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>type</B><CODE> </CODE>tkey<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>type</B><CODE> </CODE>tinfo<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>type</B><CODE> </CODE>t<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>create<CODE> </CODE><CODE>:</CODE><CODE> </CODE>unit<CODE> </CODE>-&gt;<CODE> </CODE>t<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>add<CODE> </CODE><CODE>:</CODE><CODE> </CODE>tkey<CODE> </CODE>-&gt;<CODE> </CODE>tinfo<CODE> </CODE>-&gt;<CODE> </CODE>t<CODE> </CODE>-&gt;<CODE> </CODE>unit<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>nth<CODE> </CODE><CODE>:</CODE><CODE> </CODE>int<CODE> </CODE>-&gt;<CODE> </CODE>t<CODE> </CODE>-&gt;<CODE> </CODE>tkey<CODE>*</CODE>tinfo<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>get<CODE> </CODE><CODE>:</CODE><CODE> </CODE><TT>(</TT>tkey<CODE> </CODE>-&gt;<CODE> </CODE>bool<TT>)</TT><CODE> </CODE>-&gt;<CODE> </CODE>t<CODE> </CODE>-&gt;<CODE> </CODE><TT>(</TT>tkey<CODE>*</CODE>tinfo<TT>)</TT><CODE> </CODE>list<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>end</B><CODE> </CODE>;;<BR>

</PRE>
<BR>
<BR>
We keep unspecified for now the types of the log keys (type
<I>tkey</I>) and of the associated data (type
<I>tinfo</I>), as well as the data structure for storing logs
(type <I>t</I>). We assume that new informations added with the
<TT>add</TT> function are kept in sequence. Two access functions are
provided: access by position in the log (function <TT>nth</TT>) and
access following a search predicate on keys (function <TT>get</TT>).<BR>
<BR>

<H5> Account statements.</H5> The last parameter of the manager
module provides two functions for editing a statement for an account:


<PRE><BR># <B>module</B><CODE> </CODE><B>type</B><CODE> </CODE>STATEMENT<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>sig</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>type</B><CODE> </CODE>tdata<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>type</B><CODE> </CODE>tinfo<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>editB<CODE> </CODE><CODE>:</CODE><CODE> </CODE>tdata<CODE> </CODE>-&gt;<CODE> </CODE>tinfo<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>editC<CODE> </CODE><CODE>:</CODE><CODE> </CODE>tdata<CODE> </CODE>-&gt;<CODE> </CODE>tinfo<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>end</B><CODE> </CODE>;;<BR>

</PRE>

We leave abstract the type of data to process (<I>tdata</I>)
as well as the type of informations extracted from the data
(<I>tinfo</I>).<BR>
<BR>
<A NAME="toc191"></A>
<H3> The Parameterized Module for Managing Accounts</H3>
Using only the information provided by the signatures above, we
now define the general-purpose functor for managing accounts.


<PRE><BR># <B>module</B><CODE> </CODE>FManager<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><B>functor</B><CODE> </CODE><TT>(</TT>C<CODE>:</CODE>ACCOUNT<TT>)</TT><CODE> </CODE>-&gt;<BR><CODE> </CODE><CODE> </CODE><B>functor</B><CODE> </CODE><TT>(</TT>K<CODE>:</CODE>OKEY<TT>)</TT><CODE> </CODE>-&gt;<BR><CODE> </CODE><CODE> </CODE><B>functor</B><CODE> </CODE><TT>(</TT>L<CODE>:</CODE>LOG<CODE> </CODE><B>with</B><CODE> </CODE><B>type</B><CODE> </CODE>tkey<CODE>=</CODE>K.t<CODE> </CODE><B>and</B><CODE> </CODE><B>type</B><CODE> </CODE>tinfo<CODE>=</CODE>float<TT>)</TT><CODE> </CODE>-&gt;<BR><CODE> </CODE><CODE> </CODE><B>functor</B><CODE> </CODE><TT>(</TT>S<CODE>:</CODE>STATEMENT<CODE> </CODE><B>with</B><CODE> </CODE><B>type</B><CODE> </CODE>tdata<CODE>=</CODE>L.t<CODE> </CODE><B>and</B><CODE> </CODE><B>type</B><CODE> </CODE>tinfo<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>=</CODE><CODE> </CODE><TT>(</TT>L.tkey<CODE>*</CODE>L.tinfo<TT>)</TT><CODE> </CODE>list<TT>)</TT><CODE> </CODE>-&gt;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>struct</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>type</B><CODE> </CODE>t<CODE> </CODE><CODE>=</CODE><CODE> </CODE>{<CODE> </CODE>accnt<CODE> </CODE><CODE>:</CODE><CODE> </CODE>C.t;<CODE> </CODE>log<CODE> </CODE><CODE>:</CODE><CODE> </CODE>L.t<CODE> </CODE>}<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>create<CODE> </CODE>s<CODE> </CODE>d<CODE> </CODE><CODE>=</CODE><CODE> </CODE>{<CODE> </CODE>accnt<CODE> </CODE><CODE>=</CODE><CODE> </CODE>C.create<CODE> </CODE>s<CODE> </CODE>d;<CODE> </CODE>log<CODE> </CODE><CODE>=</CODE><CODE> </CODE>L.create()<CODE> </CODE>}<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>deposit<CODE> </CODE>s<CODE> </CODE>g<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>C.deposit<CODE> </CODE>s<CODE> </CODE>g<CODE>.</CODE>accnt<CODE> </CODE>;<CODE> </CODE>L.add<CODE> </CODE><TT>(</TT>K.create()<TT>)</TT><CODE> </CODE>s<CODE> </CODE>g<CODE>.</CODE>log<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>withdraw<CODE> </CODE>s<CODE> </CODE>g<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>C.withdraw<CODE> </CODE>s<CODE> </CODE>g<CODE>.</CODE>accnt<CODE> </CODE>;<CODE> </CODE>L.add<CODE> </CODE><TT>(</TT>K.create()<TT>)</TT><CODE> </CODE><TT>(</TT><CODE>-.</CODE>s<TT>)</TT><CODE> </CODE>g<CODE>.</CODE>log<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>balance<CODE> </CODE>g<CODE> </CODE><CODE>=</CODE><CODE> </CODE>C.balance<CODE> </CODE>g<CODE>.</CODE>accnt<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>statement<CODE> </CODE>edit<CODE> </CODE>g<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>f<CODE> </CODE><TT>(</TT>d<CODE>,</CODE>i<TT>)</TT><CODE> </CODE><CODE>=</CODE><CODE> </CODE><TT>(</TT>K.to_string<CODE> </CODE>d<TT>)</TT><CODE> </CODE><CODE>^</CODE><CODE> </CODE><CODE>":"</CODE><CODE> </CODE><CODE>^</CODE><CODE> </CODE><TT>(</TT>string_of_float<CODE> </CODE>i<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>List.map<CODE> </CODE>f<CODE> </CODE><TT>(</TT>edit<CODE> </CODE>g<CODE>.</CODE>log<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>statementB<CODE> </CODE><CODE>=</CODE><CODE> </CODE>statement<CODE> </CODE>S.editB<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>statementC<CODE> </CODE><CODE>=</CODE><CODE> </CODE>statement<CODE> </CODE>S.editC<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>end</B><CODE> </CODE>;;<CODE> </CODE><BR><CODE>module FManager :</CODE><BR><CODE>  functor(C : ACCOUNT) -&gt;</CODE><BR><CODE>    functor(K : OKEY) -&gt;</CODE><BR><CODE>      functor</CODE><BR><CODE>        (L : sig</CODE><BR><CODE>               type tkey = K.t</CODE><BR><CODE>               and tinfo = float</CODE><BR><CODE>               and t</CODE><BR><CODE>               val create : unit -&gt; t</CODE><BR><CODE>               val add : tkey -&gt; tinfo -&gt; t -&gt; unit</CODE><BR><CODE>               val nth : int -&gt; t -&gt; tkey * tinfo</CODE><BR><CODE>               val get : (tkey -&gt; bool) -&gt; t -&gt; (tkey * tinfo) list</CODE><BR><CODE>             end) -&gt;</CODE><BR><CODE>        functor</CODE><BR><CODE>          (S : sig</CODE><BR><CODE>                 type tdata = L.t</CODE><BR><CODE>                 and tinfo = (L.tkey * L.tinfo) list</CODE><BR><CODE>                 val editB : tdata -&gt; tinfo</CODE><BR><CODE>                 val editC : tdata -&gt; tinfo</CODE><BR><CODE>               end) -&gt;</CODE><BR><CODE>          sig</CODE><BR><CODE>            type t = { accnt: C.t; log: L.t }</CODE><BR><CODE>            val create : float -&gt; float -&gt; t</CODE><BR><CODE>            val deposit : L.tinfo -&gt; t -&gt; unit</CODE><BR><CODE>            val withdraw : float -&gt; t -&gt; unit</CODE><BR><CODE>            val balance : t -&gt; float</CODE><BR><CODE>            val statement : (L.t -&gt; (K.t * float) list) -&gt; t -&gt; string list</CODE><BR><CODE>            val statementB : t -&gt; string list</CODE><BR><CODE>            val statementC : t -&gt; string list</CODE><BR><CODE>          end</CODE><BR>

</PRE>
<BR>
<BR>

<H5> Sharing between types.</H5> The type constraint over
the parameter <TT>L</TT> of the <TT>FManager</TT> functor
indicates that the keys of the log are those provided by the
<TT>K</TT> parameter, and that the informations stored in the log are
floating-point numbers (the transaction amounts). The type constraint
over the <TT>S</TT> parameter indicates that the informations
contained in the statement come from the log (the
<TT>L</TT> parameter).
The signature inferred for the <TT>FManager</TT> functor reflects the
type sharing constraints in the inferred signatures for the functor
parameters.<BR>
<BR>
The type <TT>t</TT> in the result of <TT>FManager</TT> is a pair of an
account (<TT>C.t</TT>) and its transaction log.<BR>
<BR>

<H5> Operations.</H5> All operations defined in this functor are
defined in terms of lower-level functions provided by the module
parameters. The creation, deposit and withdrawal operations affect
the contents of the account and add an entry in its transaction log. The 
other functions return the account balance and edit statements.<BR>
<BR>
<A NAME="toc192"></A>
<H3> Implementing the Parameters</H3> Before building the end
modules, we must first implement the parameters to the 
<TT>FManager</TT> module.<BR>
<BR>

<H5> Accounts.</H5>
The data structure for an account is composed of a float representing
the current balance, plus the maximum overdraft allowed. The latter
is used to check withdrawals.


<PRE><BR># <B>module</B><CODE> </CODE>Account<CODE>:</CODE>ACCOUNT<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><B>struct</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>type</B><CODE> </CODE>t<CODE> </CODE><CODE>=</CODE><CODE> </CODE>{<CODE> </CODE><B>mutable</B><CODE> </CODE>balance<CODE>:</CODE>float;<CODE> </CODE>overdraft<CODE>:</CODE>float<CODE> </CODE>}<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>exception</B><CODE> </CODE>BadOperation<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>create<CODE> </CODE>b<CODE> </CODE>o<CODE> </CODE><CODE>=</CODE><CODE> </CODE>{<CODE> </CODE>balance<CODE>=</CODE>b;<CODE> </CODE>overdraft<CODE>=</CODE><TT>(</TT><CODE>-.</CODE><CODE> </CODE>o<TT>)</TT><CODE> </CODE>}<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>deposit<CODE> </CODE>s<CODE> </CODE>c<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE> </CODE>c<CODE>.</CODE>balance<CODE> </CODE><CODE>&lt;-</CODE><CODE> </CODE>c<CODE>.</CODE>balance<CODE> </CODE><CODE>+.</CODE><CODE> </CODE>s<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>balance<CODE> </CODE>c<CODE> </CODE><CODE>=</CODE><CODE> </CODE>c<CODE>.</CODE>balance<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>withdraw<CODE> </CODE>s<CODE> </CODE>c<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>ss<CODE> </CODE><CODE>=</CODE><CODE> </CODE>c<CODE>.</CODE>balance<CODE> </CODE><CODE>-.</CODE><CODE> </CODE>s<CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>if</B><CODE> </CODE>ss<CODE> </CODE><CODE>&lt;</CODE><CODE> </CODE>c<CODE>.</CODE>overdraft<CODE> </CODE><B>then</B><CODE> </CODE>raise<CODE> </CODE>BadOperation<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>else</B><CODE> </CODE>c<CODE>.</CODE>balance<CODE> </CODE><CODE>&lt;-</CODE><CODE> </CODE>ss<BR><CODE> </CODE><CODE> </CODE><B>end</B><CODE> </CODE>;;<BR><CODE>module Account : ACCOUNT</CODE><BR>

</PRE>
<BR>
<BR>

<H5> Choosing log keys.</H5> We decide that keys for transaction logs
should be the date of the transaction, expressed as a floating-point
number as returned by the <TT>time</TT> function from module <TT>Unix</TT>.


<PRE><BR># <B>module</B><CODE> </CODE>Date<CODE>:</CODE>OKEY<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><B>struct</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>type</B><CODE> </CODE>t<CODE> </CODE><CODE>=</CODE><CODE> </CODE>float<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>create()<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Unix.time()<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>of_string<CODE> </CODE><CODE>=</CODE><CODE> </CODE>float_of_string<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>to_string<CODE> </CODE><CODE>=</CODE><CODE> </CODE>string_of_float<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>eq<CODE> </CODE><CODE>=</CODE><CODE> </CODE><TT>(</TT><CODE>=</CODE><TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>lt<CODE> </CODE><CODE>=</CODE><CODE> </CODE><TT>(</TT><CODE>&lt;</CODE><TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>gt<CODE> </CODE><CODE>=</CODE><CODE> </CODE><TT>(</TT><CODE>&gt;</CODE><TT>)</TT><BR><CODE> </CODE><CODE> </CODE><B>end</B><CODE> </CODE>;;<BR><CODE>module Date : OKEY</CODE><BR>

</PRE>
<BR>
<BR>

<H5> The log.</H5> The transaction log depends on a particular choice
of log keys. Hence we define logs as a functor parameterized by a key
structure.


<PRE><BR># <B>module</B><CODE> </CODE>FLog<CODE> </CODE><TT>(</TT>K<CODE>:</CODE>OKEY<TT>)</TT><CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><B>struct</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>type</B><CODE> </CODE>tkey<CODE> </CODE><CODE>=</CODE><CODE> </CODE>K.t<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>type</B><CODE> </CODE>tinfo<CODE> </CODE><CODE>=</CODE><CODE> </CODE>float<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>type</B><CODE> </CODE>t<CODE> </CODE><CODE>=</CODE><CODE> </CODE>{<CODE> </CODE><B>mutable</B><CODE> </CODE>contents<CODE> </CODE><CODE>:</CODE><CODE> </CODE><TT>(</TT>tkey<CODE>*</CODE>tinfo<TT>)</TT><CODE> </CODE>list<CODE> </CODE>}<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>create()<CODE> </CODE><CODE>=</CODE><CODE> </CODE>{<CODE> </CODE>contents<CODE> </CODE><CODE>=</CODE><CODE> </CODE>[]<CODE> </CODE>}<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>add<CODE> </CODE>c<CODE> </CODE>i<CODE> </CODE>l<CODE> </CODE><CODE>=</CODE><CODE> </CODE>l<CODE>.</CODE>contents<CODE> </CODE><CODE>&lt;-</CODE><CODE> </CODE><TT>(</TT>c<CODE>,</CODE>i<TT>)</TT><CODE> </CODE>::<CODE> </CODE>l<CODE>.</CODE>contents<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>nth<CODE> </CODE>i<CODE> </CODE>l<CODE> </CODE><CODE>=</CODE><CODE> </CODE>List.nth<CODE> </CODE>l<CODE>.</CODE>contents<CODE> </CODE>i<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>get<CODE> </CODE>f<CODE> </CODE>l<CODE> </CODE><CODE>=</CODE><CODE> </CODE>List.filter<CODE> </CODE><TT>(</TT><B>fun</B><CODE> </CODE><TT>(</TT>c<CODE>,_</CODE><TT>)</TT><CODE> </CODE>-&gt;<CODE> </CODE><TT>(</TT>f<CODE> </CODE>c<TT>)</TT><TT>)</TT><CODE> </CODE>l<CODE>.</CODE>contents<BR><CODE> </CODE><CODE> </CODE><B>end</B><CODE> </CODE>;;<CODE> </CODE><BR><CODE>module FLog :</CODE><BR><CODE>  functor(K : OKEY) -&gt;</CODE><BR><CODE>    sig</CODE><BR><CODE>      type tkey = K.t</CODE><BR><CODE>      and tinfo = float</CODE><BR><CODE>      and t = { mutable contents: (tkey * tinfo) list }</CODE><BR><CODE>      val create : unit -&gt; t</CODE><BR><CODE>      val add : tkey -&gt; tinfo -&gt; t -&gt; unit</CODE><BR><CODE>      val nth : int -&gt; t -&gt; tkey * tinfo</CODE><BR><CODE>      val get : (tkey -&gt; bool) -&gt; t -&gt; (tkey * tinfo) list</CODE><BR><CODE>    end</CODE><BR>

</PRE>
<BR>
<BR>
Notice that the type of informations stored in log entries must be
consistent with the type used in the account manager functor.<BR>
<BR>

<H5> Statements.</H5> We define two functions for editing
statements. The first (<TT>editB</TT>) lists the five most recent
transactions, and is intended for the bank; the second
(<TT>editC</TT>) lists all transactions performed during the last 10
days, and is intended for the customer.<BR>
<BR>


<PRE><BR># <B>module</B><CODE> </CODE>FStatement<CODE> </CODE><TT>(</TT>K<CODE>:</CODE>OKEY<TT>)</TT><CODE> </CODE><TT>(</TT>L<CODE>:</CODE>LOG<CODE> </CODE><B>with</B><CODE> </CODE><B>type</B><CODE> </CODE>tkey<CODE>=</CODE>K.t<TT>)</TT><CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><B>struct</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>type</B><CODE> </CODE>tdata<CODE> </CODE><CODE>=</CODE><CODE> </CODE>L.t<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>type</B><CODE> </CODE>tinfo<CODE> </CODE><CODE>=</CODE><CODE> </CODE><TT>(</TT>L.tkey<CODE>*</CODE>L.tinfo<TT>)</TT><CODE> </CODE>list<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>editB<CODE> </CODE>h<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>List.map<CODE> </CODE><TT>(</TT><B>fun</B><CODE> </CODE>i<CODE> </CODE>-&gt;<CODE> </CODE>L.nth<CODE> </CODE>i<CODE> </CODE>h<TT>)</TT><CODE> </CODE><CODE>[</CODE><CODE>0</CODE>;<CODE>1</CODE>;<CODE>2</CODE>;<CODE>3</CODE>;<CODE>4</CODE><CODE>]</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>editC<CODE> </CODE>h<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>c0<CODE> </CODE><CODE>=</CODE><CODE> </CODE>K.of_string<CODE> </CODE><TT>(</TT>string_of_float<CODE> </CODE><TT>(</TT><TT>(</TT>Unix.time()<TT>)</TT><CODE> </CODE><CODE>-.</CODE><CODE> </CODE><CODE>8</CODE><CODE>6</CODE><CODE>4</CODE><CODE>0</CODE><CODE>0</CODE><CODE>0</CODE><CODE>.</CODE><TT>)</TT><TT>)</TT><CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>f<CODE> </CODE><CODE>=</CODE><CODE> </CODE>K.lt<CODE> </CODE>c0<CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>L.get<CODE> </CODE>f<CODE> </CODE>h<BR><CODE> </CODE><CODE> </CODE><B>end</B><CODE> </CODE>;;<BR><CODE>module FStatement :</CODE><BR><CODE>  functor(K : OKEY) -&gt;</CODE><BR><CODE>    functor</CODE><BR><CODE>      (L : sig</CODE><BR><CODE>             type tkey = K.t</CODE><BR><CODE>             and tinfo</CODE><BR><CODE>             and t</CODE><BR><CODE>             val create : unit -&gt; t</CODE><BR><CODE>             val add : tkey -&gt; tinfo -&gt; t -&gt; unit</CODE><BR><CODE>             val nth : int -&gt; t -&gt; tkey * tinfo</CODE><BR><CODE>             val get : (tkey -&gt; bool) -&gt; t -&gt; (tkey * tinfo) list</CODE><BR><CODE>           end) -&gt;</CODE><BR><CODE>      sig</CODE><BR><CODE>        type tdata = L.t</CODE><BR><CODE>        and tinfo = (L.tkey * L.tinfo) list</CODE><BR><CODE>        val editB : L.t -&gt; (L.tkey * L.tinfo) list</CODE><BR><CODE>        val editC : L.t -&gt; (L.tkey * L.tinfo) list</CODE><BR><CODE>      end</CODE><BR>

</PRE>
<BR>
<BR>
In order to define the 10-day statement, we need to know exactly the
implementation of keys as floats. This arguably goes against the
principles of type abstraction. However, the key corresponding to ten
days ago is obtained from its string representation by calling the
<TT>K.of_string</TT> function, instead of directly computing the
internal representation of this date. (Our example is probably too
simple to make this subtle distinction obvious.)<BR>
<BR>

<H5> End modules.</H5> To build the modules
<TT>MBank</TT> and <TT>MCustomer</TT>, for use by the bank and the
customer respectively, we proceed as follows:
<OL type=1>
<LI>
 define a common ``account manager'' structure by application of
the <TT>FManager</TT> functor;

<LI> declare two signatures listing only the functions accessible to the
bank or to the customer;

<LI> constrain the structure obtained in 1 with the signatures
declared in 2.
</OL>


<PRE><BR># <B>module</B><CODE> </CODE>Manager<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE>FManager<CODE> </CODE><TT>(</TT>Account<TT>)</TT><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><TT>(</TT>Date<TT>)</TT><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><TT>(</TT>FLog<TT>(</TT>Date<TT>)</TT><TT>)</TT><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><TT>(</TT>FStatement<CODE> </CODE><TT>(</TT>Date<TT>)</TT><CODE> </CODE><TT>(</TT>FLog<TT>(</TT>Date<TT>)</TT><TT>)</TT><TT>)</TT><CODE> </CODE>;;<BR><CODE>module Manager :</CODE><BR><CODE>  sig</CODE><BR><CODE>    type t =</CODE><BR><CODE>      FManager(Account)(Date)(FLog(Date))(FStatement(Date)(FLog(Date))).t =</CODE><BR><CODE>      { accnt: Account.t;</CODE><BR><CODE>        log: FLog(Date).t }</CODE><BR><CODE>    val create : float -&gt; float -&gt; t</CODE><BR><CODE>    val deposit : FLog(Date).tinfo -&gt; t -&gt; unit</CODE><BR><CODE>    val withdraw : float -&gt; t -&gt; unit</CODE><BR><CODE>    val balance : t -&gt; float</CODE><BR><CODE>    val statement :</CODE><BR><CODE>      (FLog(Date).t -&gt; (Date.t * float) list) -&gt; t -&gt; string list</CODE><BR><CODE>    val statementB : t -&gt; string list</CODE><BR><CODE>    val statementC : t -&gt; string list</CODE><BR><CODE>  end</CODE><BR>

</PRE>



<PRE><BR># <B>module</B><CODE> </CODE><B>type</B><CODE> </CODE>MANAGER_BANK<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>sig</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>type</B><CODE> </CODE>t<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>create<CODE> </CODE><CODE>:</CODE><CODE> </CODE>float<CODE> </CODE>-&gt;<CODE> </CODE>float<CODE> </CODE>-&gt;<CODE> </CODE>t<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>deposit<CODE> </CODE><CODE>:</CODE><CODE> </CODE>float<CODE> </CODE>-&gt;<CODE> </CODE>t<CODE> </CODE>-&gt;<CODE> </CODE>unit<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>withdraw<CODE> </CODE><CODE>:</CODE><CODE> </CODE>float<CODE> </CODE>-&gt;<CODE> </CODE>t<CODE> </CODE>-&gt;<CODE> </CODE>unit<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>balance<CODE> </CODE><CODE>:</CODE><CODE> </CODE>t<CODE> </CODE>-&gt;<CODE> </CODE>float<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>statementB<CODE> </CODE><CODE>:</CODE><CODE> </CODE>t<CODE> </CODE>-&gt;<CODE> </CODE><CODE> </CODE>string<CODE> </CODE>list<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>end</B><CODE> </CODE>;;<BR>

</PRE>



<PRE><BR># <B>module</B><CODE> </CODE>MBank<CODE> </CODE><CODE>=</CODE><CODE> </CODE><TT>(</TT>Manager<CODE>:</CODE>MANAGER_BANK<CODE> </CODE><B>with</B><CODE> </CODE><B>type</B><CODE> </CODE>t<CODE>=</CODE>Manager.t<TT>)</TT><CODE> </CODE>;;<BR><CODE>module MBank :</CODE><BR><CODE>  sig</CODE><BR><CODE>    type t = Manager.t</CODE><BR><CODE>    val create : float -&gt; float -&gt; t</CODE><BR><CODE>    val deposit : float -&gt; t -&gt; unit</CODE><BR><CODE>    val withdraw : float -&gt; t -&gt; unit</CODE><BR><CODE>    val balance : t -&gt; float</CODE><BR><CODE>    val statementB : t -&gt; string list</CODE><BR><CODE>  end</CODE><BR>

</PRE>



<PRE><BR># <B>module</B><CODE> </CODE><B>type</B><CODE> </CODE>MANAGER_CUSTOMER<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>sig</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>type</B><CODE> </CODE>t<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>deposit<CODE> </CODE><CODE>:</CODE><CODE> </CODE>float<CODE> </CODE>-&gt;<CODE> </CODE>t<CODE> </CODE>-&gt;<CODE> </CODE>unit<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>withdraw<CODE> </CODE><CODE>:</CODE><CODE> </CODE>float<CODE> </CODE>-&gt;<CODE> </CODE>t<CODE> </CODE>-&gt;<CODE> </CODE>unit<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>balance<CODE> </CODE><CODE>:</CODE><CODE> </CODE>t<CODE> </CODE>-&gt;<CODE> </CODE>float<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>statementC<CODE> </CODE><CODE>:</CODE><CODE> </CODE>t<CODE> </CODE>-&gt;<CODE> </CODE><CODE> </CODE>string<CODE> </CODE>list<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>end</B><CODE> </CODE>;;<BR>

</PRE>



<PRE><BR># <B>module</B><CODE> </CODE>MCustomer<CODE> </CODE><CODE>=</CODE><CODE> </CODE><TT>(</TT>Manager<CODE>:</CODE>MANAGER_CUSTOMER<CODE> </CODE><B>with</B><CODE> </CODE><B>type</B><CODE> </CODE>t<CODE>=</CODE>Manager.t<TT>)</TT><CODE> </CODE>;;<CODE> </CODE><BR><CODE>module MCustomer :</CODE><BR><CODE>  sig</CODE><BR><CODE>    type t = Manager.t</CODE><BR><CODE>    val deposit : float -&gt; t -&gt; unit</CODE><BR><CODE>    val withdraw : float -&gt; t -&gt; unit</CODE><BR><CODE>    val balance : t -&gt; float</CODE><BR><CODE>    val statementC : t -&gt; string list</CODE><BR><CODE>  end</CODE><BR>

</PRE>
<BR>
<BR>
In order for accounts created by the bank to be usable by clients, we
added the type constraint on <I>Manager.t</I> in the definition of
the <TT>MBank</TT> and <TT>MCustomer</TT> structures, to ensure that
their <I>t</I> type components are compatible.<BR>
<BR>
<BR>
<BR>

<BR>
<BR>
 <BR>
<BR>
<HR>
<A HREF="book-ora132.html"><IMG SRC ="previous_motif.gif" ALT="Previous"></A>
<A HREF="index.html"><IMG SRC ="contents_motif.gif" ALT="Contents"></A>
<A HREF="book-ora134.html"><IMG SRC ="next_motif.gif" ALT="Next"></A>
</BODY>
</HTML>
